package breath;

import java.io.Serializable;

/**
 * Created by liyang on 16/9/12.
 */

public class BreathDetection {

    private BreathData breathData = new BreathData();


    public BreathData getBreathData() {
        return breathData;
    }

    public final static int ALGO_BREATH_CHAR_ARRAY_LEN = 5;//找多少个峰谷 上位机可以放多个

    public float ALGO_HUMIDITY_VALUE_TH = 0.1f;//滤值
    public float ALGO_HUMIDITY_DEAD_ZONE = 0.01f;//死区 处理噪声
    int filter_counter = 0;//数组值
    float[] humi_y = new float[]{0, 0, 0};//滤波器的输出
    float[] humi_x = new float[]{0, 0, 0};//滤波器的输入 换小波滤波器  5阶滤波器 代通滤波器
    float last_diff = 0;
    public final static int ALGO_FILTER_ORDER = 2;
    int breath_status;//状态变量
    public int mask_status = ALGO_MASK_OFF;//戴上取下
    public int breath_char_index, breath_char_fills, breath_data_len, flag_new_breath_char;
    float[] filter_a = new float[]{1, -0.7612f, 0.0945f};//滤波器的边界  算法工具算出来的
    float[] filter_b = new float[]{0.5473f, 0, -0.5473f};

    public final static int BREATH_STATUS_IDEL = 0;
    public final static int BREATH_STATUS_INHALE = 1;
    public final static int BREATH_STATUS_EXHALE = 2;

    public final static int ALGO_MASK_OFF = 1;
    public final static int ALGO_MASK_ON = 0;

    public BreathDetection.breath_char[] breath_char_t;
    public BreathDetection.breath_char[] breath_char;//存的 峰谷 特征值

    public int APP_RTC_TIMER_DELAY;//
    public int ALGO_DURATION_TH = 10;//峰 跟谷的时间长度

    public BreathDetection() {
        breath_char = new breath_char[5];
        for (int i = 0; i < breath_char.length; i++) {
            breath_char[i] = new breath_char();
        }
    }

    public BreathDetection(float v1, float v2) {
        this.ALGO_HUMIDITY_VALUE_TH = v1;//滤值  小于这个是
        this.ALGO_HUMIDITY_DEAD_ZONE = v2;//死区 处理噪声
        breath_char = new breath_char[5];
        for (int i = 0; i < breath_char.length; i++) {
            breath_char[i] = new breath_char();
        }
    }

    long tempTime;
    long tempTime2;
    DateItem dateItem;

    static float lowpass_filter_a[] = {1.0000f, -1.5610f, 0.6414f};
    static float lowpass_filter_b[] = {0.0201f, 0.0402f, 0.0201f};
    //    static float lowpass_filter_b[] = {0.0201f, 0.0402f, 0.0201f};
    float breath_humidity_th = ALGO_HUMIDITY_VALUE_TH;
    static final int ALGO_HUMIDITY_VALUE_TH_MIN = 10;
    public static final int DO_INIT = 0;
    int temp_filter_counter = 0;
    static final int count = 10;
    float humi_y2[] = new float[count];
    float humi_x2[] = new float[count];


    public float lowpass_filter(float humidity) {
        if (temp_filter_counter < 2) {
            humi_y2[1 - temp_filter_counter] = humidity;
            humi_x2[1 - temp_filter_counter] = humidity;
            temp_filter_counter++;
            return 1;
        } else {
            float sum;
            sum = lowpass_filter_b[0] * humidity
                    + lowpass_filter_b[1] * humi_x2[0]
                    + lowpass_filter_b[2] * humi_x2[1];
            sum -= lowpass_filter_a[1] * humi_y2[0] + lowpass_filter_a[2] * humi_y2[1];

            humi_x2[1] = humi_x2[0];
            humi_x2[0] = humidity;

            humi_y2[1] = humi_y2[0];
            humi_y2[0] = sum;
            //breath_humidity_th = (80 - sum/1000) * user.humi_th_cali;   user.humi_th_cali = 1;
//                breath_humidity_th = (((float) 890 / 8 - sum *(102.4f/111.75f)) * 1);

            breath_humidity_th = (890 / 8 - sum / 10.0f * 9f / 8f);

            breath_humidity_th = (breath_humidity_th > 100) ? 100 :
                    breath_humidity_th < ALGO_HUMIDITY_VALUE_TH_MIN ?
                            ALGO_HUMIDITY_VALUE_TH_MIN : breath_humidity_th;

            float temp= (sum > 90) ? 0.15f : 1;
            temp = temp > 1 ? 1 : temp;
//            System.out.println(humidity + "=======" + breath_humidity_th + "===========" + (breath_humidity_th / 100)
//                    + "======" + sum + "====="
//                    + tempxx * ALGO_HUMIDITY_VALUE_TH);
            System.out.println(humidity + "============" + temp + "=========" + sum);
            return temp;
//			breath_humidity_th *= 3;

        }
    }

    public DateItem breath_detection(float temperature, float humidity) {
        dateItem = new DateItem();
        dateItem.humidity = humidity;
        dateItem.temperature = temperature;
        dateItem.ts = System.currentTimeMillis();
        dateItem.p = 0;
        dateItem.type = 1;

        float temp = lowpass_filter(humidity);
        if (filter_counter < ALGO_FILTER_ORDER) {// 数组赋值
            // pipe line is should be filled
            humi_y[ALGO_FILTER_ORDER - filter_counter - 1] = humidity;
            humi_x[ALGO_FILTER_ORDER - filter_counter - 1] = humidity;
            filter_counter++;
        } else {
            float sum;

            sum = filter_b[0] * humidity + filter_b[1] * humi_x[0] + filter_b[2] * humi_x[1];
            sum -= filter_a[1] * humi_y[0] + filter_a[2] * humi_y[1];

            humi_x[1] = humi_x[0];
            humi_x[0] = humidity;

            humi_y[1] = humi_y[0];
            humi_y[0] = sum;
//            Intent intent = new Intent(UtilsBroadcast.ACTION_FLUSH_BREATE_DATA_TURBOMODEL2);
//            intent.putExtra(Constants.EXTRA_DATA, humidity + "====" + sum);
//            UtilsBroadcast.sendBroadcast(intent);
            // diff
            float diff = humi_y[0] - humi_y[1];

            if (Math.abs(diff) < (ALGO_HUMIDITY_DEAD_ZONE * temp)) {
                diff = 0;
            }
            System.out.println(diff);
            if (breath_status != BREATH_STATUS_IDEL) {
                if (last_diff > 0 && diff <= 0) {
                    // exit exhale
                    breath_status = BREATH_STATUS_IDEL;
                    breath_char[breath_char_index].duration = System.currentTimeMillis()
                            - (breath_char[breath_char_index].start_time);// 当前时间-
                    // 开始时间
//
//                  if (breath_char[breath_char_index].duration == 0) {
//                      // __asm("BKPT #0\n");
//                  }

                    breath_char_index++;
                    breath_char_index = (breath_char_index == ALGO_BREATH_CHAR_ARRAY_LEN) ? 0 : breath_char_index;
                    flag_new_breath_char = 1;

                    breath_char_fills++;
                    breath_char_fills = breath_char_fills > ALGO_BREATH_CHAR_ARRAY_LEN ? ALGO_BREATH_CHAR_ARRAY_LEN
                            : breath_char_fills;
                } else if (last_diff < 0 && diff >= 0) {
                    // exit inhale
                    breath_status = BREATH_STATUS_IDEL;
                    breath_char[breath_char_index].duration = System.currentTimeMillis()
                            - (breath_char[breath_char_index].start_time);// 当前时间-
                    // 开始时间
                    // + (float) (rtc_clock.subsec -
                    // breath_char[breath_char_index].start_time.subsec)
                    // * APP_RTC_TIMER_DELAY / 100;

                    if (breath_char[breath_char_index].duration == 0) {
                        // __asm("BKPT #0\n");
                    }

                    breath_char_index++;
                    breath_char_index = (breath_char_index == ALGO_BREATH_CHAR_ARRAY_LEN) ? 0 : breath_char_index;
                    flag_new_breath_char = 1;

                    breath_char_fills++;
                    breath_char_fills = breath_char_fills > ALGO_BREATH_CHAR_ARRAY_LEN ? ALGO_BREATH_CHAR_ARRAY_LEN
                            : breath_char_fills;
                }
            }
            if (last_diff <= 0 && diff > 0) {
                // enter exhale
                breath_status = BREATH_STATUS_EXHALE;

                breath_char[breath_char_index].start_time = System.currentTimeMillis();
                // breath_char[breath_char_index].start_time =
                // System.currentTimeMillis();
            } else if (last_diff >= 0 && diff < 0) {
                // enter inhale
                breath_status = BREATH_STATUS_INHALE;

                breath_char[breath_char_index].start_time = System.currentTimeMillis();
                // breath_char[breath_char_index].start_time =
                // System.currentTimeMillis();
            }
            last_diff = diff;

            switch (breath_status) {
                case BREATH_STATUS_EXHALE:
                    if (diff > breath_char[breath_char_index].value) {
                        breath_char[breath_char_index].value = diff;
                    }
                    break;
                case BREATH_STATUS_INHALE:
                    if (diff < breath_char[breath_char_index].value) {
                        breath_char[breath_char_index].value = diff;
                    }
                    break;
                default:
                    break;
            }
            if (humidity == 0) {
                flag_new_breath_char = 1;
            }
            if (breath_char_fills > 1 && flag_new_breath_char == 1) {
                // System.out.println(humidity);
                int discard = 0;
                flag_new_breath_char = 0;

                int breath_char_cur_index = (breath_char_index == 0) ? (ALGO_BREATH_CHAR_ARRAY_LEN - 1)
                        : (breath_char_index - 1);

                // the breath char is fully filled, should run PR
                // LAW A, two char start time should not very much larger then
                // duration
                long dur32 = 0;

                // dur32 = (breath_char[breath_char_cur_index].start_time -
                // breath_char[(breath_char_cur_index == 0
                // ? (ALGO_BREATH_CHAR_ARRAY_LEN - 1) : (breath_char_cur_index -
                // 1))].start_time) * 10;
                dur32 = (breath_char[breath_char_cur_index].start_time - breath_char[(breath_char_cur_index == 0
                        ? (ALGO_BREATH_CHAR_ARRAY_LEN - 1) : (breath_char_cur_index - 1))].start_time);

                if (dur32 > (breath_char[(breath_char_cur_index == 0 ? (ALGO_BREATH_CHAR_ARRAY_LEN - 1)
                        : (breath_char_cur_index - 1))].duration * ALGO_DURATION_TH)) {//时间太大了
                    discard = 1;

                    // #ifdef ALGO_DEBUG_LOG_ON
                    // char string[8] = "LAW A DI";
                    // send_debug_info((uint8_t *)string, 8);
                    // hex2Ascii_s7( dur32 , string);
                    // send_debug_info((uint8_t *)string, 8);
                    // #endif
                }

                dur32 = (System.currentTimeMillis() - breath_char[breath_char_cur_index].start_time);
                tempTime = dur32;
                tempTime2 = breath_char[breath_char_cur_index].duration * ALGO_DURATION_TH;
                if (dur32 > breath_char[breath_char_cur_index].duration * ALGO_DURATION_TH) {
                    discard = 1;

                    // #ifdef ALGO_DEBUG_LOG_ON
                    // char string[8] = "LAW A2DI";
                    // send_debug_info((uint8_t *)string, 8);
                    // hex2Ascii_s7( dur32 , string);
                    // send_debug_info((uint8_t *)string, 8);
                    // #endif
                }
                if (discard == 1) {
                    // keep the last breath_char, discard all others
                    breath_char_fills = 1;
                    if (mask_status == ALGO_MASK_ON) {
                        mask_status = ALGO_MASK_OFF;
                        // do stop_time save and breath data save here

                        algo_log_stop_time(breath_char[breath_char_cur_index].start_time);
                        // save the last unsaved breath data here
                        int save_index = (breath_char_index == (ALGO_BREATH_CHAR_ARRAY_LEN - 1)) ? 0
                                : (breath_char_index + 1);
                        for (int i = save_index; i == breath_char_cur_index; i = (i == (ALGO_BREATH_CHAR_ARRAY_LEN - 1)
                                ? 0 : (i + 1))) {
                            breath_data_len++;

                            // dur32 = (breath_char[i].start_time
                            // - breath_char[(i == 0) ?
                            // (ALGO_BREATH_CHAR_ARRAY_LEN - 1) : (i -
                            // 1)].start_time)
                            // * 10;
                            dur32 = (breath_char[i].start_time
                                    - breath_char[(i == 0) ? (ALGO_BREATH_CHAR_ARRAY_LEN - 1) : (i - 1)].start_time);

                            // dur32 = dur32 % 0x100;
                            algo_log_breath_data(dur32, breath_data_len);
                        }

                        // save data len
                        algo_log_breath_data_len(breath_data_len);
                        breath_data_len = 0;
                    }
                }

                // LAW B, values should not less then pre-set thershold
                if (Math.abs(breath_char[breath_char_cur_index].value) < (temp * ALGO_HUMIDITY_VALUE_TH)) {
                    // #ifdef ALGO_DEBUG_LOG_ON
                    // char string[8] = "LAW B DI";
                    // send_debug_info((uint8_t *)string, 8);
                    // hex2Ascii_s7((int32_t)breath_char[breath_char_cur_index].value,
                    // string);
                    // send_debug_info((uint8_t *)string, 8);
                    // #endif
                    // //only discard the current char,
                    // discard = 2;
                }

                if (discard == 2) {
                    // discard the last breath_char
                    breath_char_index = (breath_char_index == 0) ? (ALGO_BREATH_CHAR_ARRAY_LEN - 1)
                            : (breath_char_index - 1);

                    breath_char_fills = (breath_char_fills == 0) ? (ALGO_BREATH_CHAR_ARRAY_LEN - 1)
                            : (breath_char_fills - 1);
                }

                // LAW C(Put ON), should at least some breath char be found
                if (breath_char_fills == ALGO_BREATH_CHAR_ARRAY_LEN) {
                    if (mask_status == ALGO_MASK_OFF) {
                        // mask on first detected

                        mask_status = ALGO_MASK_ON;
                        algo_log_start_time(breath_char[breath_char_index].start_time);
                        algo_log_is_inhale(breath_char[breath_char_index].value < 0 ? 1 : 0);
                        breath_data_len = 0;
                        // __asm("BKPT #0\n");
                    }
                    // mask_status already on
                    breath_data_len++;

                    // dur32 = breath_char[breath_char_cur_index].start_time;
                    dur32 = (breath_char[breath_char_cur_index].start_time - breath_char[(breath_char_cur_index == 0)
                            ? (ALGO_BREATH_CHAR_ARRAY_LEN - 1) : (breath_char_cur_index - 1)].start_time);

                    // dur32 = dur32 % 0x100;
                    algo_log_breath_data(dur32, breath_data_len);
                }
            }
        }

//        Intent intent = new Intent(BlueService.ACTION_DATA__DATE_ITEM);
//        intent.putExtra(BlueService.EXTRA_DATA, dateItem);
//        LocalBroadcastManager.getInstance(AppCurr.getInstance()).sendBroadcast(intent);
        return dateItem;
    }

    // public void algo_log_stop_time(long time){
    //
    // }

    public void algo_log_breath_data(long dur, int position) {
        breathData.breathList.add(new Long(dur).intValue());


        dateItem.ts = breathData.start + dur;

        if (breathData.startBreath) {
            if (position % 2 == 0) {
                dateItem.type = 2;
            } else {
                dateItem.type = 3;
            }
        } else {
            if (position % 2 == 0) {
                dateItem.type = 3;
            } else {
                dateItem.type = 2;
            }
        }

        System.out.println("algo_log_breath_data=======" + dur + "====" + position);
        if (position % 2 == 0) {
//            UtilsBroadcast.sendBroadcast(UtilsBroadcast.ACTION_FLUSH_BREATE_DATA_TURBOMODEL);
        }

    }

    ;

    public void algo_log_stop_time(long time) {
        breathData.end = time;
        breathData.count = breathData.breathList.size() / 2;
        dateItem.endTime = time;
        System.out.println("algo_log_stop_time=======" + time);

    }


    public void algo_log_start_time(long time) {
        breathData.start = time;
        dateItem.startTime = time;
        System.out.println("algo_log_start_time=======" + time);
    }


    public void algo_log_breath_data_len(long len) {
        System.out.println("algo_log_breath_data_len=======" + len);
    }

    ;

    void algo_log_is_inhale(int isInhale) {
        breathData.startBreath = isInhale == 1 ? true : false;
        System.out.println("algo_log_is_inhale=======" + isInhale);

    }

    ;


    class breath_char {
        long start_time;
        long duration;
        float value;

        @Override
        public String toString() {
            return "breath_char [start_time=" + start_time + ", duration=" + duration + ", value=" + value + "]";
        }
    }

    public static class DateItem implements Serializable {
        public long ts;
        public String value;
        public float temperature;
        public float humidity;
        public float p;
        public int type;//1数据 2呼 3吸

        public long startTime;//开始时间
        public long endTime;//结束时间

        public String getValue() {
            switch (type) {
                case 1:
                    return temperature + " / " + humidity;
                case 2:
                    return "呼 / " + temperature + " / " + humidity;
                case 3:
                    return "吸 / " + temperature + " / " + humidity;
            }
            return "";
        }
    }
}
